/*
 * libwbxml, the WBXML Library.
 * Copyright (C) 2002-2008 Aymerick Jehanne <aymerick@jehanne.org>
 * Copyright (C) 2011 Michael Bell <michael.bell@opensync.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * LGPL v2.1: http://www.gnu.org/copyleft/lesser.txt
 *
 * Contact: aymerick@jehanne.org
 * Home: http://libwbxml.aymerick.com
 */

/**
 * @file wbxml_conv.c
 * @ingroup wbxml_conv
 *
 * @author Aymerick Jehanne <aymerick@jehanne.org>
 * @date 03/02/23
 *
 * @brief WBXML Convertion Library (XML to WBXML, and WBXML to XML)
 */

#include "wbxml_conv.h"
#include "wbxml_tree.h"
#include "wbxml_log.h"

#ifdef WITH_NIF
#include "erl_nif.h"
#endif

/****************************
 *    converter objects     *
 ****************************
 */

struct WBXMLConvWBXML2XML_s {
    WBXMLGenXMLType gen_type;    /**< WBXML_GEN_XML_COMPACT | WBXML_GEN_XML_INDENT | WBXML_GEN_XML_CANONICAL (Default: WBXML_GEN_XML_INDENT) */
    WBXMLLanguage lang;          /**< Force document Language (overwrite document Public ID) */
    WBXMLCharsetMIBEnum charset; /**< Set document Language (does not overwrite document character set) */
    WB_UTINY indent;             /**< Indentation Delta, when using WBXML_GEN_XML_INDENT Generation Type (Default: 0) */
    WB_BOOL keep_ignorable_ws;   /**< Keep Ignorable Whitespaces (Default: FALSE) */
};

struct WBXMLConvXML2WBXML_s {
    WBXMLVersion wbxml_version; /**< WBXML Version */
    WB_BOOL keep_ignorable_ws;  /**< Keep Ignorable Whitespaces (Default: FALSE) */
    WB_BOOL use_strtbl;         /**< Generate String Table (Default: TRUE) */
    WB_BOOL produce_anonymous;  /**< Produce an anonymous document (Default: FALSE) */
};

/****************************
 *     Public Functions     *
 ****************************
 */

WBXML_DECLARE(WBXMLError) wbxml_conv_wbxml2xml_create(WBXMLConvWBXML2XML **conv)
{
    *conv = (WBXMLConvWBXML2XML *) wbxml_malloc(sizeof(WBXMLConvWBXML2XML));
    if (conv == NULL) {
        return WBXML_ERROR_NOT_ENOUGH_MEMORY;
    }
    
    (*conv)->gen_type = WBXML_GEN_XML_INDENT;
    (*conv)->lang     = WBXML_LANG_UNKNOWN;
    (*conv)->charset  = WBXML_CHARSET_UNKNOWN;
    (*conv)->indent   = 0;
    (*conv)->keep_ignorable_ws = FALSE;
    
    return WBXML_OK;
}

/**
 * @brief Set the XML generation type (default: WBXML_GEN_XML_INDENT).
 * @param conv     [in] the converter
 * @param gen_type [in] generation type
 */
WBXML_DECLARE(void) wbxml_conv_wbxml2xml_set_gen_type(WBXMLConvWBXML2XML *conv, WBXMLGenXMLType gen_type)
{
    conv->gen_type = gen_type;
}

/**
 * @brief Set the used WBXML language.
 *        The language is usually detected by the specified public ID in the document.
 *        If the public ID is set then it overrides the language.
 * @param conv [in] the converter
 * @param lang [in] language (e.g. SYNCML12)
 */
WBXML_DECLARE(void) wbxml_conv_wbxml2xml_set_language(WBXMLConvWBXML2XML *conv, WBXMLLanguage lang)
{
    conv->lang = lang;
}

/**
 * @brief Set the used character set.
 *        The default character set is UTF-8.
 *        If the document specifies a character set by it own
 *        then this character set overrides the parameter charset.
 * @param conv    [in] the converter
 * @param charset [in] the character set
 */
WBXML_DECLARE(void) wbxml_conv_wbxml2xml_set_charset(WBXMLConvWBXML2XML *conv, WBXMLCharsetMIBEnum charset)
{
    conv->charset = charset;
}

/**
 * @brief Set the indent of the generated XML document (please see EXPAT default).
 * @param conv   [in] the converter
 * @param indent [in] the number of blanks
 */
WBXML_DECLARE(void) wbxml_conv_wbxml2xml_set_indent(WBXMLConvWBXML2XML *conv, WB_UTINY indent)
{
    conv->indent = indent;
}

/**
 * @brief Enable whitespace preservation (default: FALSE).
 * @param conv     [in] the converter
 */
WBXML_DECLARE(void) wbxml_conv_wbxml2xml_enable_preserve_whitespaces(WBXMLConvWBXML2XML *conv)
{
    conv->keep_ignorable_ws = TRUE;
}

/**
 * @brief Convert WBXML to XML
 * @param conv      [in] the converter
 * @param wbxml     [in] WBXML Document to convert
 * @param wbxml_len [in] Length of WBXML Document
 * @param xml       [out] Resulting XML Document
 * @param xml_len   [out] XML Document length
 * @return WBXML_OK if conversion succeeded, an Error Code otherwise
 */
WBXML_DECLARE(WBXMLError) wbxml_conv_wbxml2xml_run(WBXMLConvWBXML2XML *conv,
                                                   WB_UTINY  *wbxml,
                                                   WB_ULONG   wbxml_len,
                                                   WB_UTINY **xml,
                                                   WB_ULONG  *xml_len)
{
    WBXMLGenXMLParams params;
    WBXMLTree *wbxml_tree = NULL;
    WB_ULONG   dummy_len = 0;
    WBXMLError ret = WBXML_OK;
    
    /* Copy options */
    params.gen_type          = conv->gen_type;
    params.lang              = conv->lang;
    params.charset           = conv->charset;
    params.keep_ignorable_ws = conv->keep_ignorable_ws;
    params.indent            = conv->indent;
    
    /* Check Parameters (we allow 'xml_len' to be NULL for backward compatibility) */
    if ((wbxml == NULL) || (wbxml_len == 0) || (xml == NULL))
        return WBXML_ERROR_BAD_PARAMETER;
    
    if (xml_len == NULL)
        xml_len = &dummy_len;
    
    *xml = NULL;
    *xml_len = 0;
    
    /* Parse WBXML to WBXML Tree */
    ret = wbxml_tree_from_wbxml(wbxml, wbxml_len, conv->lang, conv->charset, &wbxml_tree);
    if (ret != WBXML_OK) {
        WBXML_ERROR((WBXML_CONV, "wbxml2xml conversion failed - WBXML Parser Error: %s",
                     wbxml_errors_string(ret)));
        
        return ret;
    }
    else {
        /* Convert Tree to XML */
        ret = wbxml_tree_to_xml(wbxml_tree, xml, xml_len, &params);
        if (ret != WBXML_OK) {
            WBXML_ERROR((WBXML_CONV, "wbxml2xml conversion failed - WBXML Encoder Error: %s",
                         wbxml_errors_string(ret)));
        }
        
        /* Clean-up */
        wbxml_tree_destroy(wbxml_tree);
        
        return ret;
    }
}

/**
 * @brief Destroy the converter object.
 * @param [in] the converter
 */
WBXML_DECLARE(void) wbxml_conv_wbxml2xml_destroy(WBXMLConvWBXML2XML *conv)
{
    wbxml_free(conv);
}

/**
 * @brief Create a new WBXML to XML converter with the default configuration.
 * @param conv [out] a reference to the pointer of the new converter
 * @return WBXML_OK if conversion succeeded, an Error Code otherwise
 */
WBXML_DECLARE(WBXMLError) wbxml_conv_xml2wbxml_create(WBXMLConvXML2WBXML **conv)
{
    *conv = (WBXMLConvXML2WBXML *) wbxml_malloc(sizeof(WBXMLConvXML2WBXML));
    if (conv == NULL) {
        return WBXML_ERROR_NOT_ENOUGH_MEMORY;
    }
    
    (*conv)->wbxml_version     = WBXML_VERSION_13;
    (*conv)->keep_ignorable_ws = FALSE;
    (*conv)->use_strtbl        = TRUE;
    (*conv)->produce_anonymous = FALSE;
    
    return WBXML_OK;
}

/**
 * @brief Set the WBXML version (default: 1.3).
 * @param conv   [in] the converter
 * @param indent [in] the number of blanks
 */
WBXML_DECLARE(void) wbxml_conv_xml2wbxml_set_version(WBXMLConvXML2WBXML *conv,
                                                     WBXMLVersion wbxml_version)
{
    conv->wbxml_version = wbxml_version;
}

/**
 * @brief Enable whitespace preservation (default: FALSE/DISABLED).
 * @param conv     [in] the converter
 */
WBXML_DECLARE(void) wbxml_conv_xml2wbxml_enable_preserve_whitespaces(WBXMLConvXML2WBXML *conv)
{
    conv->keep_ignorable_ws = TRUE;
}

/**
 * @brief Disable string table (default: TRUE/ENABLED).
 * @param conv     [in] the converter
 */
WBXML_DECLARE(void) wbxml_conv_xml2wbxml_disable_string_table(WBXMLConvXML2WBXML *conv)
{
    conv->use_strtbl = FALSE;
}

/**
 * @brief Disable public ID (default: TRUE/ENABLED).
 * @param conv     [in] the converter
 */
WBXML_DECLARE(void) wbxml_conv_xml2wbxml_disable_public_id(WBXMLConvXML2WBXML *conv)
{
    conv->produce_anonymous = TRUE;
}

/**
 * @brief Convert XML to WBXML
 * @param conv      [in] the converter
 * @param xml       [in] XML Document to convert
 * @param xml_len   [in] Length of XML Document
 * @param wbxml     [out] Resulting WBXML Document
 * @param wbxml_len [out] Length of resulting WBXML Document
 * @return WBXML_OK if conversion succeeded, an Error Code otherwise
 */
WBXML_DECLARE(WBXMLError) wbxml_conv_xml2wbxml_run(WBXMLConvXML2WBXML *conv,
                                                   WB_UTINY  *xml,
                                                   WB_ULONG   xml_len,
                                                   WB_UTINY **wbxml,
                                                   WB_ULONG  *wbxml_len)
{
    WBXMLTree *wbxml_tree = NULL;
    WBXMLError ret = WBXML_OK;
    WBXMLGenWBXMLParams params;
    
    /* Check Parameters */
    if ((xml == NULL) || (xml_len == 0) || (wbxml == NULL) || (wbxml_len == NULL))
        return WBXML_ERROR_BAD_PARAMETER;
    
    /* copy options */
    params.wbxml_version     = conv->wbxml_version;
    params.keep_ignorable_ws = conv->keep_ignorable_ws;
    params.use_strtbl        = conv->use_strtbl;
    params.produce_anonymous = conv->produce_anonymous;
    
    *wbxml = NULL;
    *wbxml_len = 0;
    
    /* Parse XML to WBXML Tree */
    ret = wbxml_tree_from_xml(xml, xml_len, &wbxml_tree);
    if (ret != WBXML_OK) {
        WBXML_ERROR((WBXML_CONV, "xml2wbxml conversion failed - Error: %s",
                     wbxml_errors_string(ret)));
        
        return ret;
    }
    else {
        /* Convert Tree to WBXML */
        ret = wbxml_tree_to_wbxml(wbxml_tree, wbxml, wbxml_len, &params);
        if (ret != WBXML_OK) {
            WBXML_ERROR((WBXML_CONV, "xml2wbxml conversion failed - WBXML Encoder Error: %s",
                         wbxml_errors_string(ret)));
        }
        
        /* Clean-up */
        wbxml_tree_destroy(wbxml_tree);
        
        return ret;
    }
}


/**
 * @brief Destroy the converter object.
 * @param [in] the converter
 */
WBXML_DECLARE(void) wbxml_conv_xml2wbxml_destroy(WBXMLConvXML2WBXML *conv)
{
    wbxml_free(conv);
}

/**************************************
 * Public Functions - DEPRECATED in API
 */

WBXML_DECLARE(WBXMLError) wbxml_conv_wbxml2xml_withlen(WB_UTINY  *wbxml,
                                                       WB_ULONG   wbxml_len,
                                                       WB_UTINY **xml,
                                                       WB_ULONG  *xml_len,
                                                       WBXMLGenXMLParams *params)
{
    WBXMLConvWBXML2XML *conv = NULL;
    WBXMLError ret = WBXML_OK;
    
    ret = wbxml_conv_wbxml2xml_create(&conv);
    if (ret != WBXML_OK)
        return ret;
    
    wbxml_conv_wbxml2xml_set_gen_type(conv, params->gen_type);
    wbxml_conv_wbxml2xml_set_language(conv, params->lang);
    wbxml_conv_wbxml2xml_set_charset(conv, params->charset);
    wbxml_conv_wbxml2xml_set_indent(conv, params->indent);
    if (params->keep_ignorable_ws)
        wbxml_conv_wbxml2xml_enable_preserve_whitespaces(conv);
    ret = wbxml_conv_wbxml2xml_run(conv, wbxml, wbxml_len, xml, xml_len);
    wbxml_conv_wbxml2xml_destroy(conv);
    return ret;
}

WBXML_DECLARE(WBXMLError) wbxml_conv_xml2wbxml_withlen(WB_UTINY  *xml,
                                                       WB_ULONG   xml_len,
                                                       WB_UTINY **wbxml,
                                                       WB_ULONG  *wbxml_len,
                                                       WBXMLGenWBXMLParams *params)
{
    WBXMLConvXML2WBXML *conv = NULL;
    WBXMLError ret = WBXML_OK;
    
    ret = wbxml_conv_xml2wbxml_create(&conv);
    if (ret != WBXML_OK)
        return ret;
    
    wbxml_conv_xml2wbxml_set_version(conv, params->wbxml_version);
    if (params->keep_ignorable_ws)
        wbxml_conv_xml2wbxml_enable_preserve_whitespaces(conv);
    if (!params->use_strtbl)
        wbxml_conv_xml2wbxml_disable_string_table(conv);
    if (params->produce_anonymous)
        wbxml_conv_xml2wbxml_disable_public_id(conv);
    ret = wbxml_conv_xml2wbxml_run(conv, xml, xml_len, wbxml, wbxml_len);
    wbxml_conv_xml2wbxml_destroy(conv);
    return ret;
}


/**
 *Using dynamic buffer instead
 *#define BUFF_LEN 8192
 **/
#define BUFF_LEN 8192

#define CONV_LEN 6
char *conv_string[CONV_LEN][2]={{"stream:stream","stream_stream"},
				{"stream:features","stream_features"},
				{"xmlns:stream","xmlns_stream"},
				{"xml:lang","xml_lang"},
				{"xmlns","snlmx"},
				{"stream:error","stream_error"}};

char *xmlver="<?xml version=\"1.0\"?>";
char *dtd="<!DOCTYPE www PUBLIC \"-//WAPFORUM//DTD XMPP 1.0//EN\" \"http://www.xmpp.org/DTD/xmpp.dtd\">";
char *endstream="\n</stream_stream>";
char *endstream1="</stream:stream>";
char end[8]={0xff,0xff,0xff,0xff,0x0f,0x0f,0x0f,0xfe};
char space[8]=" \t \t \t ";
#define SPACE_LEN 7
char *oems="<oem_tag>";
char *oeme="</oem_tag>";
unsigned char endchar=0xFE;

WBXML_DECLARE(WBXMLError) wbxml_to_xml(WB_UTINY *wbxml,WB_ULONG wbxml_len, WB_UTINY *xml,WB_ULONG *xml_len){
    WBXMLError ret = WBXML_OK;
    WBXMLConvWBXML2XML *conv = NULL;
    
    WB_UTINY *newxml=NULL;
    int i=0;
    
    unsigned char *p=NULL,*q,*ptr,*pw;
    unsigned char *tmp=NULL;
    unsigned char *buff=NULL;
    unsigned char *xml_buff=NULL;
    
    /** changed 123
     unsigned char tmp[BUFF_LEN];
     unsigned char buff[BUFF_LEN];
     unsigned char xml_buff[BUFF_LEN];
     **/
    
    int xml_buff_len=0;
    int len =wbxml_len;
    
    //10 is enough
    tmp= (unsigned char*)malloc (wbxml_len*10);
    buff = (unsigned char*)malloc(wbxml_len*10);
    xml_buff = (unsigned char*)malloc(wbxml_len*10);
    /**  changed 123
     if(wbxml_len >= BUFF_LEN){
     #ifdef WITH_NIF
     syslog(6,"wbxml2xml failed:wbxml is too long");
     #endif
     return -1;
     }
     */
    memcpy(buff,wbxml,wbxml_len);
    ptr=buff;
    while(*ptr!=endchar && len > 0){
        pw=ptr;
        while(*ptr!=endchar && len >0){
            ptr++;
            len--;
        }
        
        if(*ptr!=endchar){
#ifdef WITH_NIF
            syslog(6,"wbxml2xml:wbxml has no end ,left length %d",ptr-pw);
#endif
            break;
        }
        ptr++;len--;
        
        wbxml_len=ptr-pw;
        memcpy(wbxml,pw,wbxml_len);
        
        
        if(memcmp(wbxml,end,8)==0){
            strcpy(xml,endstream1);
            *xml_len=strlen(endstream1);
            //Only end stream  changed 123
            if(tmp)
                free(tmp);
            if(buff)
                free(buff);
            if(xml_buff)
                free(xml_buff);
            //End of chanted 123
            return ret;
        }
        if(memcmp(wbxml,space,SPACE_LEN)==0){
            
            //Changed 123
            if(tmp)
                free(tmp);
            if(buff)
                free(buff);
            if(xml_buff)
                free(xml_buff);
            //End of Changed 123
            
            //ret should be WBXML_OK  here   OK returned , but no data copy to xml buffer?
            
            return ret;
        }
        
        wbxml_len-=1;
        
        ret = wbxml_conv_wbxml2xml_create(&conv);
        if(ret!=WBXML_OK){
#ifdef WITH_NIF
            syslog(6,"wbxml2xml failed:%s",wbxml_errors_string(ret));
#endif
            //  changed 123
            if(tmp)
                free(tmp);
            if(buff)
                free(buff);
            if(xml_buff)
                free(xml_buff);
            //End of chanted 123
            return ret;
        }
        ret = wbxml_conv_wbxml2xml_run(conv, wbxml, wbxml_len, &newxml, xml_len);
        if (ret != WBXML_OK) {
#ifdef WITH_NIF
            syslog(6,"xml2wbxml failed:%s",wbxml_errors_string(ret));
#endif
            wbxml_conv_wbxml2xml_destroy(conv);
            if(newxml!=NULL){
#ifdef WBXML_USE_LEAKTRACKER
                wbxml_free(newxml);
#else
                free(newxml);
#endif
                newxml=NULL;
            }
            //  changed 123
            if(tmp)
                free(tmp);
            if(buff)
                free(buff);
            if(xml_buff)
                free(xml_buff);
            //End of chanted 123
            
            return ret;
        }
        
        wbxml_conv_wbxml2xml_destroy(conv);
        
        newxml[*xml_len]='\0';
        for(i=0;i<CONV_LEN;i++){
            p=newxml;
            q=NULL;
            
            while((q=strstr(p,conv_string[i][1]))!=NULL){
                memcpy(q,conv_string[i][0],strlen(conv_string[i][0]));
                p=q+strlen(conv_string[i][0]);
            }
        }
        
        if((p=strstr(newxml,"<stream:stream"))!=NULL){
            strcpy(xml,xmlver);
            strcat(xml,p);
            *xml_len=strlen(xml);
            q=xml + *xml_len -1;
            while(*q!='>')q--;
            q--;
            while(*q!='/')q--;
            *q=' ';
            
        }else {
            p=strstr(newxml,oems);
            if(p==NULL){
#ifdef WITH_NIF
                syslog(6,"wbxml2xml failed:[%s]",newxml);
#endif
                goto end;
            }
            while(*p!='>')p++;
            p++;
            strcpy(xml,p);
            p=strstr(xml,oeme);
            *p='\0';
            *xml_len=strlen(xml);
        }
        
        p=xml;
        q=tmp;
        while(*p!='\0'){
            if(*p!='\n'){
                *q=*p;
                q++;
            }
            p++;
        }
        *q='\0';
        
        //strcpy(xml,tmp);
        *xml_len=strlen(tmp);
        
        memcpy(xml_buff+xml_buff_len,tmp,*xml_len);
        xml_buff_len+=*xml_len;
    end:
        
        if(newxml!=NULL){
#ifdef WBXML_USE_LEAKTRACKER
            wbxml_free(newxml);
#else
            free(newxml);
#endif
            newxml=NULL;
        }
        
    }
    
    memcpy(xml,xml_buff,xml_buff_len);
    *xml_len=xml_buff_len;
    xml[xml_buff_len]='\0';
    
    
    //  changed 123
    if(tmp)
        free(tmp);
    if(buff)
        free(buff);
    if(xml_buff)
        free(xml_buff);
    //End of chanted 123
    
    if (xml_buff_len <= 0) {
        return WBXML_ERROR_NULL_PARSER;
    }
    
    return ret;
}

WBXML_DECLARE(WBXMLError) xml_to_wbxml(WB_UTINY *xml,WB_ULONG xml_len, WB_UTINY *wbxml,WB_ULONG *wbxml_len){
    WBXMLError ret = WBXML_OK;
    WBXMLConvXML2WBXML *conv = NULL;
    
    WB_UTINY *newwbxml=NULL;
    
    int i=0;
    unsigned char *p=NULL,*q;
    //Changed 123
    //char newxml[BUFF_LEN];
    char *newxml = NULL;
    newxml = (char*)malloc(xml_len+300);
    //End of changed 123
    
    
    /**  Changed 123
     if(xml_len >= BUFF_LEN-200){
     #ifdef WITH_NIF
     syslog(6,"xml2wbxml failed:xml is too long");
     #endif
     return -1;
     }
     End of changed 123 **/
    
    xml[xml_len]='\0';
    for(i=0;i<CONV_LEN;i++){
        p=xml;
        q=NULL;
        
        while((q=strstr(p,conv_string[i][0]))!=NULL){
            if(i != 4 || (i==4 && q[5]!='_') ){
                memcpy(q,conv_string[i][1],strlen(conv_string[i][1]));
            }
            p=q+strlen(conv_string[i][0]);
        }
    }
    
    if((p=strstr(xml,"<stream_stream"))!=NULL){
        strcpy(newxml,xmlver);
        strcat(newxml,dtd);
        strcat(newxml,p);
        strcat(newxml,endstream);
        xml_len=strlen(newxml);
    }else if(strstr(xml,"</stream_stream>")!=NULL){
        memcpy(wbxml,end,8);
        *wbxml_len=8;
        //Changed 123
        if(newxml!=NULL)
            free(newxml);
        //End of chaned 123
        return ret;
    }else if(strstr(xml,"<")==NULL){
        memcpy(wbxml,space,SPACE_LEN);
        wbxml[SPACE_LEN]=endchar;
        *wbxml_len=SPACE_LEN+1;
        //Changed 123
        if(newxml!=NULL)
            free(newxml);
        //End of chaned 123
        
        return ret;
    }else {
        strcpy(newxml,xmlver);
        strcat(newxml,dtd);
        strcat(newxml,oems);
        strcat(newxml,xml);
        strcat(newxml,oeme);
        xml_len+=strlen(xmlver)+strlen(dtd)+strlen(oems)+strlen(oeme);
    }
    
    
    ret = wbxml_conv_xml2wbxml_create(&conv);
    if(ret!=WBXML_OK){
#ifdef WITH_NIF
        syslog(6,"xml2wbxml failed:%s",wbxml_errors_string(ret));
#endif
        //Changed 123
        if(newxml!=NULL)
            free(newxml);
        //End of chaned 123
        
        return ret;
    }
    ret = wbxml_conv_xml2wbxml_run(conv,newxml,xml_len,&newwbxml,wbxml_len);
    if (ret != WBXML_OK) {
#ifdef WITH_NIF
        syslog(6,"xml2wbxml failed:%s [%s]",wbxml_errors_string(ret),newxml);
#endif
    }else{
        memcpy(wbxml,newwbxml,*wbxml_len);
        wbxml[*wbxml_len]=endchar;
        *wbxml_len+=1;
    }
    
    wbxml_conv_xml2wbxml_destroy(conv);
    
    if(newwbxml!=NULL){
#ifdef WBXML_USE_LEAKTRACKER
        wbxml_free(newwbxml);
#else
        free(newwbxml);
#endif
    }
    
    //Changed 123
    if(newxml!=NULL)
        free(newxml);
    //End of chaned 123
    
    return ret;
}

#ifdef WITH_NIF
static ERL_NIF_TERM wbxml2xml(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]){
    unsigned char xml[BUFF_LEN];
    int xml_len=0;
    
    unsigned char wbxml[BUFF_LEN];
    int wbxml_len;
    
    int ret=WBXML_OK;
    
    
    if(argc<2 || !enif_is_number(env,argv[1]) || !enif_is_list(env,argv[0]) ){
        return enif_make_string(env, "bad paramater", ERL_NIF_LATIN1); 
    }else{
        memset(wbxml,0,BUFF_LEN);
        enif_get_int(env,argv[1],&wbxml_len);
        enif_get_string(env,argv[0],wbxml,wbxml_len+1,ERL_NIF_LATIN1);
    }   
    
    if(wbxml_len <= 3){
        return enif_make_string(env, "", ERL_NIF_LATIN1); 
    }
    
    memset(xml,0,BUFF_LEN);
    /*	
     int i;
     char tmp[1024];
     char s[10];
     memset(tmp,0,1024);
     strcpy(tmp,"wbxml is 0X ");
     for(i=0;i<wbxml_len;i++){
     sprintf(s,"%u ",wbxml[i]);
     strcat(tmp,s);	
     }	
     syslog(6,"wbxml len is %d %s",wbxml_len,tmp);
     */
    ret=wbxml_to_xml(wbxml,wbxml_len,xml,&xml_len);
    if(ret!=WBXML_OK){
        return enif_make_string(env, "convert to xml error", ERL_NIF_LATIN1); 
    }   
    
    return enif_make_string(env, xml, ERL_NIF_LATIN1); 
}

static ERL_NIF_TERM xml2wbxml(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]){
    unsigned char xml[BUFF_LEN];
    int xml_len=0;
    
    unsigned char wbxml[BUFF_LEN];
    int wbxml_len=0;
    
    int ret=WBXML_OK;
    
    ErlNifBinary* bin;
    
    if(argc<2 || !enif_is_number(env,argv[1]) || !enif_is_list(env,argv[0]) ){
        return enif_make_string(env, "bad paramater", ERL_NIF_LATIN1);
    }else{
        memset(xml,0,BUFF_LEN);
        enif_get_int(env,argv[1],&xml_len);
        enif_get_string(env,argv[0],xml,xml_len+1,ERL_NIF_LATIN1);
        xml[xml_len]='\0';
    }
    
    memset(wbxml,0,BUFF_LEN);
    ret=xml_to_wbxml(xml,xml_len,wbxml,&wbxml_len);
    if(ret!=WBXML_OK){
        return enif_make_string(env, "convert to wbxml error", ERL_NIF_LATIN1);
    }
    
    return enif_make_string_len(env,wbxml,wbxml_len,ERL_NIF_LATIN1);
}

static ErlNifFunc nif_funcs[] =
{
    {"wbxml2xml", 2, wbxml2xml},
    {"xml2wbxml", 2, xml2wbxml}
};


ERL_NIF_INIT(nif_wbxml,nif_funcs,NULL,NULL,NULL,NULL)

#endif
